package cn.juque.jdfsystem.interceptor;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import cn.hutool.jwt.signers.AlgorithmUtil;
import cn.hutool.jwt.signers.JWTSigner;
import cn.hutool.jwt.signers.JWTSignerUtil;
import cn.juque.common.base.BaseOperator;
import cn.juque.common.base.BaseResponseVO;
import cn.juque.common.constants.MessageEnum;
import cn.juque.common.constants.TreeNodeConstants;
import cn.juque.common.thread.BaseOperatorThreadLocal;
import cn.juque.jdfsystem.contants.BusinessConstants;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.Map;

/**
 * @author juque
 * @version 1.0.0
 * <ul>
 *     <li>LoginInterceptor</li>
 * </ul>
 * @date 2023-01-09 09:43:20
 **/
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 获取token
        String token = request.getHeader(BusinessConstants.TOKEN_HEADER);
        if (CharSequenceUtil.isEmpty(token)) {
            BaseResponseVO<Boolean> responseVO = new BaseResponseVO<>(MessageEnum.NO_LOGIN, false);
            this.print(response, responseVO);
            return false;
        }
        token = CharSequenceUtil.subAfter(token, BusinessConstants.TOKEN_PREFIX, false);
        // 校验有效期
        JWT jwt = JWTUtil.parseToken(token);
        Map<String, Object> payload = jwt.getPayloads();
        String userId = payload.getOrDefault(BusinessConstants.USER_ID, CharSequenceUtil.EMPTY).toString();
        JWTSigner jwtSigner = JWTSignerUtil.createSigner(AlgorithmUtil.getId("HS256"), userId.getBytes(StandardCharsets.UTF_8));
        if (!JWTUtil.verify(token, jwtSigner)) {
            BaseResponseVO<Boolean> responseVO = new BaseResponseVO<>(MessageEnum.NO_LOGIN, false);
            this.print(response, responseVO);
            return false;
        }
        Long expireTime = (Long) payload.get(BusinessConstants.EXPIRE_TIME);
        if (null == expireTime || expireTime < System.currentTimeMillis()) {
            BaseResponseVO<Boolean> responseVO = new BaseResponseVO<>(MessageEnum.NO_LOGIN, false);
            this.print(response, responseVO);
            return false;
        }
        BaseOperator baseOperator = new BaseOperator();
        baseOperator.setOperatorId(userId);
        baseOperator.setUserId(userId);
        baseOperator.setOperatorName(payload.get(BusinessConstants.USER_NAME).toString());
        baseOperator.setOrgIdList(CollUtil.newArrayList(TreeNodeConstants.ROOT_CHAR));
        baseOperator.setOperatorTime(new Date());
        BaseOperatorThreadLocal baseOperatorThreadLocal = SpringUtil.getBean(BaseOperatorThreadLocal.class);
        baseOperatorThreadLocal.set(baseOperator);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        BaseOperatorThreadLocal baseOperatorThreadLocal = SpringUtil.getBean(BaseOperatorThreadLocal.class);
        baseOperatorThreadLocal.remove();
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }

    /**
     * 输出消息
     *
     * @param response   HttpServletResponse
     * @param responseVO BaseResponseVO
     */
    private void print(HttpServletResponse response, BaseResponseVO<?> responseVO) {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        try{
            response.getWriter().write(new ObjectMapper().writeValueAsString(responseVO));
            response.getWriter().flush();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }
}
